Skip to content

src: use cgroups to get memory limits#27508

Closed
kjin wants to merge 1 commit into
nodejs:masterfrom
kjin:res-limits
Closed

src: use cgroups to get memory limits#27508
kjin wants to merge 1 commit into
nodejs:masterfrom
kjin:res-limits

Conversation

@kjin

@kjin kjin commented May 1, 2019

Copy link
Copy Markdown
Contributor

This PR improves the way we set the memory ceiling for a Node.js process. Previously we would use the physical memory size (from libuv) to estimate the necessary V8 heap sizes. The physical memory size is not necessarily the correct limit, e.g. if the process is running inside a docker container or is otherwise constrained.

This change adds the ability to get a memory limit set by linux cgroups, which is used by docker containers to set resource constraints.

I've created a "resource limits" namespace/class that maybe should be the interface through which all resource constraint parameters are retrieved. So far that is just the memory limit but this could be expanded to other cgroups controller params. Also, this functionality is not necessarily specific to linux, so it's possible to have other implementations for other platforms (though this change is primarily motivated by the docker use case). Currently, behavior for other platforms besides linux is unchanged.

See also this article about support for cgroups in Java.

cc/ @ofrobots

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • commit message follows commit guidelines

@nodejs-github-bot nodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. lib / src Issues and PRs related to general changes in the lib or src directory. labels May 1, 2019
Comment thread src/node_resource_limits.h Outdated
Comment thread src/node_resource_limits.cc Outdated
Comment thread src/node_resource_limits.cc Outdated
Comment thread src/node_resource_limits.cc Outdated
Comment thread src/node_resource_limits.cc Outdated
@mscdex

mscdex commented May 1, 2019

Copy link
Copy Markdown
Contributor

Shouldn't this be done at the libuv layer in its uv_get_total_memory() implementation instead?

@ofrobots

ofrobots commented May 1, 2019

Copy link
Copy Markdown
Contributor

IMO, heuristics about resource management of the runtime belong in Node, specially once we expand this to tune the background thread-pool based on the number of available CPU cores. The act of reading/parsing the cgroups file could be in libuv, but it wouldn't fit into the uv_get_total_memory() interface, because that does something else. Personally I think there is little to gain by putting this in libuv though.

Comment thread src/api/environment.cc Outdated
Comment thread src/node_resource_limits.cc Outdated
Comment thread src/node_resource_limits.cc Outdated
Comment thread src/node_resource_limits.cc Outdated
@bnoordhuis

Copy link
Copy Markdown
Member

Shouldn't this be done at the libuv layer in its uv_get_total_memory() implementation instead?

I recently rewrote the linux implementation of uv_get_total_memory() (libuv/libuv#2258) but I decided against reading from /proc/fs/cgroups. I'm willing to be convinced that it should though.

@ofrobots

ofrobots commented May 1, 2019

Copy link
Copy Markdown
Contributor

I would expect uv_get_total_memory() to report total memory indeed. If this goes into libuv, then it probably needs to be new API.

@kjin

kjin commented May 1, 2019

Copy link
Copy Markdown
Contributor Author

I agree that it would also make sense to have this in the libuv layer; let me explore that some more. And yes, I also agree it would be a different API.

@ChALkeR

ChALkeR commented May 22, 2019

Copy link
Copy Markdown
Member

#27805 seems to use uv_get_constrained_memory().
Would that be helpful here instead of manual logic?

@kjin

kjin commented May 22, 2019

Copy link
Copy Markdown
Contributor Author

Yes, I was planning to update this PR once libuv 1.29 landed on master (which I now realize it has).

@ChALkeR

ChALkeR commented May 22, 2019

Copy link
Copy Markdown
Member

@kjin Yes, I see that you are the author of uv_get_constrained_memory() 😄, just wanted to clarify that this shouldn't duplicate that functionality. Thanks!

@ChALkeR

ChALkeR commented May 22, 2019

Copy link
Copy Markdown
Member

Under which exact circumstances does this increase the memory ceiling?

libuv doc states:

it is not unusual for this value to be less than or greater than uv_get_total_memory.

Also,

This function currently only returns a non-zero value on Linux, based on cgroups if it is present.

So this doesn't seem to be a throw-in replacement to uv_get_total_memory as it is used here?

@kjin

kjin commented May 22, 2019

Copy link
Copy Markdown
Contributor Author

@ChALkeR Ah, I just updated it to take the min of uv_get_constrained_memory and uv_get_total_memory. I don't think this change should increase the memory ceiling, at least certainly not to the unlimited value that is suggested by uv_get_constrained_memory.

Edit: Ack, I should also make sure to check that it's non-zero, doing that now.

@ChALkeR

ChALkeR commented May 22, 2019

Copy link
Copy Markdown
Member

@kjin And what about it possibly being zero? (Sorry, I updated the comment in #27508 (comment) shortly after I posted it).

@kjin

kjin commented May 22, 2019

Copy link
Copy Markdown
Contributor Author

@ChALkeR Ok, I've updated that, thanks.

@ofrobots ofrobots added the notable-change PRs with changes that should be highlighted in changelogs. label May 22, 2019
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@ChALkeR ChALkeR left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, given the current state of libuv/libuv#2323, I expect that cgroup2 support will land in libuv in the foreseeable future.

I am fine with merging this to master at this point.

That said, if we want tests for this, we probably need libuv/libuv#2323 to land first. But even then, the tests would be effective only on cgroup2 systems, and I think we don't have those on CI, so I wouldn't block on that.

@kjin Thanks!

@ChALkeR ChALkeR removed the tsc-agenda Issues and PRs to discuss during the meetings of the TSC. label Jun 12, 2019
@ChALkeR ChALkeR mentioned this pull request Jun 12, 2019
4 tasks
@kjin

kjin commented Jun 26, 2019

Copy link
Copy Markdown
Contributor Author

@ChALkeR Thank you! Yes, I'm working on addressing your comments on libuv/libuv#2323.

@kjin

kjin commented Jun 27, 2019

Copy link
Copy Markdown
Contributor Author

Given that I'm still actively working on libuv/libuv#2323, is it possible to land this, or are there any other action items I need to take before this can land?

@ChALkeR

ChALkeR commented Jun 27, 2019

Copy link
Copy Markdown
Member

I think this is good to land, given all the approvals and no standing concerns.
A description in the commit message won't hurt, though =).

This change adds the ability to set the memory ceiling for a Node.js process
according to a memory limit set by cgroups (via uv_get_constrained_memory),
which is used by docker containers to set resource constraints. Previously we
would use the physical memory size to estimate the necessary V8 heap sizes, but
the physical memory size is not necessarily the correct limit, e.g. if the
process is running inside a docker container or is otherwise constrained.

Non-Linux systems shouldn't be affected.
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@ofrobots

ofrobots commented Jul 3, 2019

Copy link
Copy Markdown
Contributor

Landed in 285e036.

@ofrobots ofrobots closed this Jul 3, 2019
This was referenced Jul 23, 2019
@ronag

ronag commented Jul 23, 2019

Copy link
Copy Markdown
Member

Question, how does this work with forks/threads?

@ChALkeR

ChALkeR commented Jul 24, 2019

Copy link
Copy Markdown
Member

@ronag forks share the same cgroup and the same limit here, afaik.
That's not ideal in some cases, but this change makes things better than they were.

It would be hard to introduce some more complex for forks, and it wouldn't be an uncontroversial improvement like this change is.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c++ Issues and PRs that require attention from people who are familiar with C++. lib / src Issues and PRs related to general changes in the lib or src directory. memory Issues and PRs related to the memory management or memory footprint. notable-change PRs with changes that should be highlighted in changelogs.

Projects

None yet

Development

Successfully merging this pull request may close these issues.